home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
JCSM Shareware Collection 1993 November
/
JCSM Shareware Collection - 1993-11.iso
/
cl720
/
emsif24a.lzh
/
EMSIF.DOC
next >
Wrap
Text File
|
1993-06-27
|
58KB
|
1,259 lines
EMSIF
Version-independent C Interface to LIM EMS Functions
for LIM EMS versions 3.0 and higher
EMSIF version 2.4
by James W. Birdsall
06/27/93
0. CONTENTS
-----------
0. CONTENTS
I. INTRODUCTION
I.1 WHAT IS SUPPORTED
I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
II. USING EMSIF
II.1 COMPILING AND LINKING WITH THE LIBRARIES
II.2 EMSTEST, THE EXAMPLE PROGRAM
III. PROGRAMMING WITH EMSIF
III.1 INITIALIZING THE LIBRARY
III.2 ORDINARY USE
III.3 FRAME CACHING AND ALIASING
III.4 SAVE/RESTORE
III.5 OTHER TIPS
III.6 FUNCTION GROUPING
IV. LIBRARY REFERENCE
IV.1 GLOBAL VARIABLES
IV.2 FUNCTIONS
V. ERROR CODES
V.1 INTERNAL ERRORS
V.2 EMS DRIVER ERRORS
VI. THE END
VI.1 ACKNOWLEDGEMENTS
VI.2 TRADEMARKS
I. INTRODUCTION
---------------
EMSIF provides a high-level interface to LIM EMS control functions
for common operations such as allocating, mapping, and freeing EMS, and
copying data to and from EMS. The interface has been made independent of
the EMS version implemented by the EMS driver as far as possible, so
that parameters and returned data are always in the same format, but the
EMS call most appropriate to the EMS version implemented by the driver
is used.
EMSIF is written in assembly language for speed and compactness and
assembled with Borland's Turbo Assembler (TASM) 2.5. The source code is
not compatible with the Microsoft Assembler (MASM).
I.1 WHAT IS SUPPORTED
---------------------
EMSIF expressly supports the Lotus-Intel-Microsoft (LIM) Expanded
Memory Specification (EMS) versions 3.0, 3.2, and 4.0. Versions above
4.0 are supported as 4.0. Versions below 3.0 are not supported.
Save/restore is not supported under version 3.0, and assigning names to
EMS handles and unmapping logical pages are only supported under version
4.0. These exceptions to version-independence are due to limitations of
the unsupported versions; the necessary services are not available from
the driver.
EMSIF supports tiny, small, medium, compact, large, and huge memory
models. The small model library supports both tiny and small models, so
no library is provided specifically for tiny model.
EMSIF supports any version of Turbo C, Turbo C++, or Borland C++, in
both C and C++ modes, and Microsoft C 6.00 and above. This version of
EMSIF has been tested with Borland C++ 2.0, Turbo C 2.0, Microsoft C 7.0
and 8.0 (in Microsoft Visual C++ 1.0) in all of the supported memory
models. EMSIF should work with earlier versions of Microsoft C and any
other C compiler that 1) uses compatible parameter passing and return
methods and 2) can use standard-format libraries.
I.2 COPYRIGHT, LICENSE, AND WARRANTY DISCLAIMER
-----------------------------------------------
EMSIF is not in the public domain. All the files are copyright 1991,
1992, 1993 by James W. Birdsall, all rights reserved. Permission is
granted to do the following:
You may freely redistribute this archive, so long as it contains
all the files listed in the file MANIFEST, intact and
unmodified.
You may use the libraries in programs for your own use. You may
not distribute programs linked with these libraries.
Payment of the $5 shareware registration fee ($50 for commercial use)
grants the following license, in addition to the permissions listed
above:
You may request the source to EMSIF. You may modify the source
as necessary for use in your programs. However, you may not
redistribute either the original or modified source.
You may distribute programs linked with either the original
libraries or libraries generated from source you have modified,
without royalty, provided you (a) do not alter or remove
copyright notices contained therein and (b) you indemnify, hold
harmless, and defend the author from and against any claims or
lawsuits, including attorney's fees, that arise or result from
the use or distribution of your software product.
For the purposes of this license, commercial use is defined as use by an
incorporated entity in a software product that is regarded as the
product of the corporation, no matter how the software product is
distributed, but only if 100 or more copies of the product are expected
to be made.
The contents of the distribution archive, and all other related
files, information, and services are provided "as is" and without
warranty. To the extent permitted by applicable law, the author
disclaims all warranties, express or implied, including but not limited
to, any implied warranty of merchantability or fitness for a particular
purpose. While effort has been made to ensure that the files, information,
and services are accurate and correct, the author shall not be liable
for damages arising out of the use of or inability to use this product,
including but not limited to, loss of profit, data, or use of this
software, or special, incidental, or consequential damages or other
similar claims, even if the author has been specifically advised of the
possibility of such damages. Some states do not allow the exclusion of
incidental or consequential damages, so the foregoing limitation may not
apply to you.
Information on contacting the author is provided at the end of this
file.
II. USING EMSIF
---------------
This section describes how to use the EMSIF libraries with your
programs.
II.1 COMPILING AND LINKING WITH THE LIBRARIES
---------------------------------------------
EMSIF is provided as Borland/Microsoft standard library files.
Libraries are provided for small, medium, compact, large, and huge
memory models (tiny model uses the small model library). The model for
which a library is intended is indicated by the last letter of the
filename proper, which is the same as the first letter for the model.
For example, EMSIFL.LIB is the large model library.
To use EMSIF, you must #include the file EMSIF.H in every source file
that calls EMSIF functions, accesses EMSIF global variables, or uses
#defined constants provided by EMSIF. The same EMSIF.H file supports
both C and C++.
The procedures for linking EMSIF with the rest of your program vary
according to the compiler and method you are using. In general, you must
include the appropriate library (the library corresponding to the memory
model in which you have compiled the rest of your program) in the link.
If you are compiling in the Integrated Development Environment of
Turbo/Borland C[++] or Microsoft Visual C++, include the name of the
appropriate library in the project file for your program. For example,
if you are working in the compact memory model, include EMSIFC.LIB in
your project file.
If you are using a command-line compiler (bcc, tcc, or cl) to compile
and link, simply place the full name of the appropriate EMSIF library on
the command line. For example, "bcc -mc foo.c emsifc.lib" will compile
the file "foo.c" in the compact model and link it with emsifc.lib.
If you are linking manually (using TLINK or LINK), place the name of
the appropriate library in with the other libraries. For example,
tlink c0c.obj foo.obj, foo.exe, foo.map, cc.lib emsifc.lib
or
link foo.obj, foo.exe, foo.map, emsifc.lib ;
will link the object "foo.obj" with the appropriate startup object and
standard library (LINK automatically includes the startup object and
standard library, so it is not necessary to explicitly include them) and
the compact model EMSIF library.
II.2 EMSTEST, THE EXAMPLE PROGRAM
---------------------------------
A large and complete example program and tester, EMSTEST, has been
included in this distribution. It can be compiled in any of the
supported memory models (although tiny model for all compilers and
compact model for Microsoft compilers require some contortions to do
so), with either Borland or Microsoft compilers.
The test program has four source files: EMSTEST.C, EMSTEST2.C,
EMSTEST3.C, and TESTUTIL.C; and two header files: EMSTEST.H and
TESTUTIL.H. When compiling in tiny model with Borland compilers, an
additional file, STACK.OBJ, is needed. STACK.ASM, which is the source
for STACK.OBJ, has been included for completeness.
Example makefiles have been included for Borland and Microsoft
compilers. EXMAKEBC is the example makefile for Borland C++ 2.0,
EXMAKETC is the example makefile for Turbo C[++], and EXMAKEMS is the
example makefile for Microsoft C. Complete instructions for making the
example program and using the example makefiles are included at the
beginning of each makefile. More information about the program is also
included at the beginning of EMSTEST.C.
EMSTEST requires at least eight pages (128K) of available expanded
memory and at least 200,000 bytes of available conventional memory to
run.
III. PROGRAMMING WITH EMSIF
----------------------------
This section describes how to make EMSIF calls in your program, and
details various tricks and tips which you may find useful.
III.1 INITIALIZATION
--------------------
The library initialization function EMMlibinit() _must_ be called
before any other EMSIF calls are made. All other EMSIF functions are
guaranteed to fail if called before EMMlibinit(). EMMlibinit()
determines whether an EMS driver is present and sets up various internal
and global variables necessary to the functioning of EMSIF.
III.2 ORDINARY USE
------------------
EMSIF provides several sets of functions. First, there is a set of
functions which are intended to be orthogonal with the standard C
functions malloc(), free(), and realloc(), and the Borland/Turbo C[++]
function coreleft(). These functions are EMMalloc(), EMMfree(),
EMMrealloc(), and EMMcoreleft().
Second, there is a group of functions for copying data to and from
expanded memory. These functions allow you to treat allocated blocks of
expanded memory pages as linear memory, hiding the details of page
mapping. These functions are EMMcopyto(), EMMcopyfrom(), EMMicopyto(),
EMMicopyfrom(), _EMMicopyto(), and _EMMicopyfrom().
Third, there is a group of low-level functions which allow more
direct access to EMS driver calls. These functions are EMMallocpages(),
EMMreallocpages(), EMMgetframeaddr(), EMMgetnumframe(),
EMMgetsinfraddr(), EMMmappage(), and EMMunmapframe(). With these
functions it is possible to duplicate the copying functions or access
expanded memory in other ways. Calls to these functions can be mixed
with calls to copying functions without trouble, except as noted in
section IV.2 for EMS versions below 4.0.
Fourth, there is a group of miscellaneous functions: EMMgetname(),
EMMsetname(), EMMgetversion(), EMMsave(), and EMMrestore().
Finally, there is a group of functions which affect only the
operation of EMSIF itself: _EMMenc(), _EMMdisc(), _EMMinval(),
EMMlibinit(), and EMMsrinit(). For details on all the functions listed
above, see section IV.2.
To use expanded memory, first it is necessary to allocate some. This
can be done with either EMMalloc(), which takes a size in bytes, or
EMMallocpages(), which allocates EMS pages directly. Both return a
handle which will be used to reference the allocated memory.
To access the expanded memory, you can either use the copying
functions or access it directly. The copying functions are pretty
self-explanatory, so they will not be discussed further here. Accessing
expanded memory directly is more complicated. First, it is necessary to
determine the addresses of the EMS page frames. EMS page frames 0
through 3 are available under all EMS versions and are intended for
general use. While EMS version 4.0 implementations may provide
additional page frames, they are intended for use by multitaskers such
as Quarterdeck DESQview and Microsoft Windows. These additional page
frames may appear anywhere, even in the middle of your program. Use them
only with great caution. To obtain the addresses of all page frames, use
EMMgetframeaddr(). To obtain the address of a single page frame, use
EMMgetsinfraddr(). The addresses returned by both these functions are
segment addresses and must be converted to far pointers before actually
being used.
Having decided which page frame or frames you wish to use, and
determined the necessary addresses, it is then necessary to map EMS
logical pages into the page frame(s). This is accomplished with
EMMmappage(). Once this is done, you can then access any byte in that
logical page (which is 16384 bytes long) using the far pointer created
earlier. Mapping a logical page into a page frame into which another
logical page has already been mapped causes the original logical page to
be displaced by the new logical page. A logical page may be mapped in
any number of times (although "aliasing" -- having one mapped into
multiple page frames simultaneously -- may cause unexpected results),
and a page frame can have logical pages mapped into it any number of
times (but only the last one mapped is accessible in that page frame).
Under EMS 4.0, it is possible to remove the logical page currently
mapped into a frame with EMMunmapframe(), leaving no page mapped into
that frame.
Eventually, when you are done using the EMS, use EMMfree() to
deallocate it.
The miscellaneous functions listed above allow you to determine the
EMS version supported by the driver (EMMgetversion()), to associate a
string name with an EMS handle and retrieve the name associated with an
EMS handle (EMMsetname()/EMMgetname()), and save and restore EMS page
mappings (EMMsave()/EMMrestore()). More information on the last is
available in section III.4.
The internal functions _EMMenc(), _EMMdisc(), and _EMMinval() are
discussed in section III.3 below. EMMlibinit() has already been
discussed, in section III.1, and EMMsrinit() is discussed in section
III.4 below.
Many functions return a status directly. For those functions, a
return value of 0 indicates success and a return value of EMMOOPS
indicates failure. The global variable _EMMerror contains an error code
which gives further information on why the function failed, or has value
0 if the function succeeded. Many functions return some other value
instead of a status code (0 or EMMOOPS). In these cases, the value of
_EMMerror should be checked upon return. The recommended method of
error-checking is indicated for each function in section IV.2 below.
III.3 FRAME CACHING AND ALIASING
--------------------------------
Aliasing occurs when one logical page is mapped into multiple page
frames. This can cause a variety of problems if the EMS implementation
does not support aliasing well. Frequently, data written to the page in
one frame will not be visible in other frames to which that page is
mapped. At least one common implementation displays this problem.
Frame caching is a technique used by EMSIF to attempt to speed up the
copying functions. By keeping track of the handle and logical page
number mapped into page frame 2, the copying functions can avoid
unnecessary calls to the page-mapping functions.
However, frame caching has a variety of problems. First, it assumes
that all EMS mapping activity will be performed via EMSIF, so that an
accurate record of the contents of frame 2 can be kept. If you are using
another third-party library that also uses EMS, then obviously there is
mapping activity that is not performed via EMSIF, and frame caching will
cause the copying functions to malfunction. Worse, there are some
EMS-using disk caches and ramdisks which do not properly restore the EMS
page mapping, so apparently unrelated activity such as file access can
cause the copying functions to malfunction. Because of these risks,
frame caching is off by default.
The second major problem is due to aliasing; if the copying functions
leave the last logical page accessed mapped into page frame 2, attempts
to access that logical page by mapping it into some other page frame may
produce incorrect data. Hence, for EMS versions that have unmapping
capability, the copying functions unmap the last logical page accessed
just before returning. This means that frame caching is not possible
across calls to the copying functions, only within single calls.
Frame caching is off by default. To check the current setting, inspect
the global variable _EMMframecache. If it is nonzero, frame caching is
on; if it is 0, frame caching is off. The state of frame caching is
changed via the functions _EMMenc() (enable caching) and _EMMdisc()
(disable caching).
III.4 SAVE/RESTORE
------------------
Interactions with other libraries using EMS can pose problems. If the
other library assumes that the EMS mapping will not change between calls
to it, then almost any EMSIF activity at all will interfere with the
other library. This is why save/restore capability was added to EMSIF.
Note that save/restore only works with EMS versions 3.2 and up. EMS
version 3.0 has a save/restore capability so radically different from
that in versions 3.2 and up that it cannot be consolidated under the
same interface. If you use save/restore in your program, you give up
compatibility with EMS version 3.0; fortunately 3.0 is extremely rare
these days.
The EMS specification (for versions 3.2 and up) includes calls to
save the current EMS mapping to a buffer in memory, and restore a
mapping from such a buffer. EMSIF's save/restore functions are an
interface to these calls. Before any save/restore calls can be made,
EMMsrinit() must be called to initialize save/restore. It takes a single
parameter, which is a pointer to a function used to allocate save
buffers. Malloc() may be passed in any memory model, but any other
function with the same prototype may be used. Note that the passed
function will never be required to allocate more that 255 bytes in one
call.
Having initialized save/restore, you can call EMMsave() to save a
mapping and EMMrestore() to restore one. The pointer returned by
EMMsave() is the value returned by an internal call to the function
which was passed to EMMsrinit(), and may be freed when necessary with
whatever function would ordinarily be called; for example, if malloc()
was passed to EMMsrinit(), then pointers returned by EMMsave() may be
passed to free(). Note that EMMrestore() does not free save buffers. You
must free them yourself.
To avoid interference with libraries which assume that the EMS
mapping will not change, simply call EMMsave() after calls to that
library, and call EMMrestore() with the pointer returned by the last
EMMsave() before the next call to that library. Note that EMMrestore()
invalidates the frame cache, if frame caching is enabled.
Save/restore can also be used to quickly alternate between several
complex mappings. Having established a mapping, save it with EMMsave().
Then, when you need it again, a call to EMMrestore() will restore it
quickly and easily. A given mapping may be restored from the same buffer
any number of times.
III.5 OTHER TIPS
----------------
Expanded memory is not deallocated automatically when a program
exits. If the program does not deallocate expanded memory it has
allocated, that expanded memory is stuck, not available to any other
program until the machine is rebooted. Under normal circumstances, it is
easy enough to free expanded memory when it is no longer needed.
However, an emergency exit due to the user hitting control-break or due
to a hardware error (e.g. the famous "Abort, Retry, Fail?") can cause
expanded memory to become stuck unless your program takes special
measures to intercept these errors and perform cleanup before exiting.
There are a number of ways to do this and they vary from compiler to
compiler. Look for functions such as ctrlbrk(), harderr(), and signal().
If you are copying array elements, _EMMicopyto()/_EMMicopyfrom() or
EMMicopyto()/EMMicopyfrom() may be more efficient. These functions allow
copying of elements of fixed size which are separated by gaps also of
fixed size. For example, if you have an array of integers and wish to
copy all the even-indexed elements (a[0], a[2], a[4], etc.), these
functions are far faster than calling a standard copying function
(EMMcopyto() or EMMcopyfrom()) from within a loop. While the performance
improvement varies from machine to machine, the smallest speed increase
that I have seen is seven times, ranging up to over twenty times on a
fast machine with frame caching off.
III.6 FUNCTION GROUPING
-----------------------
The EMSIF functions have been arranged in the library in such a way
as to reduce the number of unnecessary functions linked into your
program. There are currently five groups:
FUNCTIONS VARIABLES
--------- ---------
GROUP 1: EMMlibinit(), EMMgetversion(), _EMMerror, _EMMversion,
EMMgetnumframe(), EMMgetsinfraddr(), _EMMframecache,
EMMgetframeaddr(), EMMmappage(), emsif_vers_vers,
EMMunmapframe() emsif_vers_date,
emsif_vers_time
GROUP 2: EMMcoreleft(), EMMallocpages(), none
EMMalloc(), EMMreallocpages(),
EMMrealloc(), EMMfree()
GROUP 3: EMMcopyto(), EMMcopyfrom(), none
_EMMicopyto(), _EMMicopyfrom(),
_EMMenc(), _EMMdisc()
GROUP 4: EMMsrinit(), EMMsave(), EMMrestore() none
GROUP 5: EMMgetname(), EMMsetname() none
If your program references any of the functions or variables in a group,
all the functions and variables in that group will be linked in. Note
that group one will always be linked, since it contains EMMlibinit(),
which all EMSIF-using programs must call.
IV. LIBRARY REFERENCE
---------------------
IV.1 GLOBAL VARIABLES
---------------------
_EMMerror
---------
unsigned char const _EMMerror;
_EMMerror contains the error code from the last EMSIF call. If the
call succeeded, _EMMerror will be 0. If the call failed because the EMS
driver returned an error, _EMMerror contains the error code returned by
the EMS driver. If the call failed because EMSIF detected an error
internally, _EMMerror contains an intenal error code. A list of error
code values, their meanings, and #defined constants for them is in
section V.
_EMMframecache
--------------
unsigned char const _EMMframecache;
_EMMframecache is a flag which indicates whether frame caching is
enabled or not. A nonzero value indicates that frame caching is enabled,
and 0 indicates that frame caching is disabled. See section III.3 for a
discussion of frame caching.
_EMMversion
-----------
unsigned char const _EMMversion;
_EMMversion contains the EMS version implemented by the EMS driver in
packed BCD format. For example, if the EMS version is 4.0, the value of
_EMMversion will be 0x40. If _EMMversion is 0x32, the EMS version is
3.2. This value is the same as that returned by EMMgetversion().
emsif_vers_vers, emsif_vers_date, emsif_vers_time
-------------------------------------------------
char const emsif_vers_vers[];
char const emsif_vers_date[];
char const emsif_vers_time[];
These are null-terminated strings containing information about the
name and version of the library, the date of assembly, and the time of
assembly, respectively.
IV.2 FUNCTIONS
--------------
_EMMdisc() - disable frame caching
----------
void _EMMdisc(void);
void _EMMenc(void);
void _EMMinval(void);
_EMMdisc() disables frame caching, invalidates the current cache
contents, and sets _EMMframecache to zero. _EMMerror should be checked
after calling this function. It is not an error to call this function
when frame caching is already disabled.
_EMMenc() enables frame caching, invalidates the current cache
contents, and sets _EMMframecache to a nonzero value. _EMMerror should
be checked after calling this function. It is not an error to call this
function when frame caching is already enabled; however, the current
cache contents will still be invalidated.
_EMMinval() is a macro (in C) or inline function (in C++) that
invalidates the current cache contents if frame caching is enabled, or
has no effect if frame caching is disabled. The frame caching status is
not changed. _EMMerror should be checked afterwards.
For more information on frame caching, see section III.3.
_EMMenc() - enable frame caching
---------
void _EMMenc(void);
See _EMMdisc();
_EMMicopyfrom() - copy data by intervals from EMS
---------------
int _EMMicopyfrom(unsigned long nelem, int elsize,
unsigned int srcskip, int handle, unsigned long foffset,
unsigned char far *dest, unsigned int destskip);
int _EMMicopyto(unsigned long nelem, int elsize,
unsigned int srcskip, unsigned char far *source,
int handle, unsigned long foffset, unsigned int destskip);
_EMMicopyfrom() allows painless copying of array elements from
expanded memory to conventional memory. EMS mapping, calculation of
addresses, skipping of unwanted elements, etc., are all handled by the
function. Elements spread across more than 64K and/or totalling more than
64K in length can be copied without special treatment.
Nelem elements are copied, each of which is elsize bytes long. The
elements are copied from the EMS pages owned by handle, starting at byte
offset foffset and with srcskip bytes between elements, to conventional
memory starting at dest with destskip bytes between elements. Dest must
be a far pointer; a near pointer can be converted to a far pointer with
a cast when the function is called. Foffset is converted as in
EMMcopyfrom().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
_EMMicopyto() allows painless copying of array elements from
conventional memory to expanded memory. EMS mapping, calculation of
addresses, skipping of unwanted elements, etc., are all handled by the
function. Elements spread across more than 64K and/or totalling more than
64K in length can be copied without special treatment.
Nelem elements are copied, each of which is elsize bytes long. The
elements are copied from conventional memory starting at source with
srcskip bytes between elements, to the EMS pages owned by handle, starting
at byte offset foffset and with destskip bytes between elements. Source
must be a far pointer; a near pointer can be converted to a far pointer
with a cast when the function is called. Foffset is converted as in
EMMcopyfrom().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
For EMS versions below 4.0, these functions leave the last logical
page accessed mapped into page frame 2 because there is no unmapping
service. This can cause trouble if you map that logical page into
another page frame in an EMS implementation that does not support
aliasing properly. If you must mix calls to EMMmappage() and the copying
functions, it is recommended that for versions below 4.0 you map some
other logical page into page frame 2 before mapping the desired page.
Alternatively, using page frame 2 to access logical pages is guaranteed
to work properly except for logical pages which you have explicitly
mapped elsewhere.
_EMMicopyto() - copy data by intervals to EMS
-------------
int _EMMicopyto(unsigned long nelem, int elsize,
unsigned int srcskip, unsigned char far *source,
int handle, unsigned long foffset, unsigned int destskip);
See _EMMicopyfrom().
_EMMinval() - invalidate frame cache contents
-----------
void _EMMinval(void);
See _EMMdisc().
EMMalloc() - allocate EMS
----------
int EMMalloc(unsigned long bytes);
int EMMallocpages(int pages);
EMMalloc() allocates EMS memory. It takes the given number of bytes
and allocates the smallest number of pages which contain that many
bytes. It returns the EMS handle assigned by the EMS driver. _EMMerror
should be checked after calling this function.
Note that EMS cannot be allocated in units smaller than a page (16384
bytes). Requesting one byte will allocate a whole page; 16385 bytes will
allocate two pages. Requesting zero bytes allocates one page.
EMMallocpages() allocates EMS memory by pages directly. It returns
the EMS handle assigned by the EMS driver. _EMMerror should be checked
after calling this function. It is possible to allocate 0 pages with
this function, but only under EMS version 4.0; under earlier versions,
allocating 0 pages is an error.
See also EMMrealloc() and EMMreallocpages().
EMMallocpages() - allocate EMS by pages
---------------
int EMMallocpages(int pages);
See EMMalloc().
EMMcopyfrom() - copy data from EMS
-------------
int EMMcopyfrom(unsigned long copylen,
int handle, unsigned long foffset,
unsigned char far *dest);
int EMMcopyto(unsigned long copylen,
unsigned char far *source,
int handle, unsigned long foffset);
EMMcopyfrom() allows painless copying of blocks of data from expanded
memory to conventional memory. All mapping, calculation of addresses,
etc., is handled by the function. Copies longer than 64K are possible
without special treatment.
Copylen bytes of data are copied, from the EMS pages owned by handle,
starting at byte offset foffset, to the conventional memory area pointed
to by dest. Dest must be a far pointer; a near pointer can be converted
to a far pointer with a cast when the function is called. Foffset ia
converted to a logical page number and offset within that page by
dividing by the size of a page (16384 bytes). The quotient is the page
number and the remainder is the offset within that page. Offsets 0
through 16383 are in page 0; offsets 16384 through 32767 are in page 1,
etc. This feature allows you to treat expanded memory blocks as linear
memory rather than a collection of pages.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror. If copylen is 0, the function
returns immediately without error.
EMMcopyto() is the mirror image of EMMcopyfrom(). It allows painless
copying of blocks of data from conventional memory to expanded memory.
All mapping, calculation of addresses, etc., is handled by the function.
Copies longer than 64K are possible without special treatment.
Copylen bytes of data are copied, from the conventional memory area
pointed to by source, to the EMS pages owned by handle, starting at byte
offset foffset. Foffset is converted as in EMMcopyfrom().
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror. If copylen is 0, the function
returns immediately without error.
For EMS versions below 4.0, these functions leave the last logical
page accessed mapped into page frame 2 because there is no unmapping
service. This can cause trouble if you map that logical page into
another page frame in an EMS implementation that does not support
aliasing properly. If you must mix calls to EMMmappage() and the copying
functions, it is recommended that for versions below 4.0 you map some
other logical page into page frame 2 before mapping the desired page.
Alternatively, using page frame 2 to access logical pages is guaranteed
to work properly except for logical pages which you have explicitly
mapped elsewhere.
See also EMMicopyto(), EMMicopyfrom(), _EMMicopyto(), and
_EMMicopyfrom().
EMMcopyto() - copy data to EMS
-----------
int EMMcopyto(unsigned long copylen,
unsigned char far *source,
int handle, unsigned long foffset);
See EMMcopyfrom().
EMMcoreleft() - get amount of free EMS
-------------
unsigned long EMMcoreleft(void);
This function returns the amount of EMS memory available, in bytes.
To determine the number of EMS pages available, divide the returned
value by 16384. _EMMerror should be checked after calling this function.
EMMfree() - deallocate EMS
---------
int EMMfree(int handle);
This function accepts an EMS handle (as returned by EMMalloc(),
EMMallocpages(), EMMrealloc(), or EMMreallocpages() or otherwise
obtained from the EMS driver) and releases it and any EMS pages
allocated to it.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMgetframeaddr() - get EMS page frame segment addresses
-----------------
int EMMgetframeaddr(frameinfo *buffer);
int EMMgetnumframe(void);
unsigned int EMMgetsinfraddr(int frame);
EMMgetframeaddr() returns the segment addresses of all the EMS page
frames. Buffer is a pointer to an array of frameinfo structures; this
array is assumed to be large enough to contain information about all the
frames. The number of frameinfo structures needed can be determined with
the EMMgetnumframe() function described below.
Each frameinfo structure contains the number and the segment address
of a frame. Check EMSIF.H or EMSIF.HPP for the exact format of the
frameinfo structure. The information is returned in whatever order the
EMS driver provides it, which is typically sorted by address rather than
frame number. Do NOT just assume that the first element in the array
contains information for frame 0! The segment addresses returned must be
converted to far pointers (using MK_FP() or your compiler's equivalent)
before they can be used to access memory.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMgetnumframe() returns the number of EMS page frames present in the
system. For EMS versions below 4.0, this will always be 4. For EMS
version 4.0, it will be at least 4.
_EMMerror should be checked after calling this function.
EMMgetsinfraddr() returns the segment address of a particular EMS
page frame. This address must be converted to a far pointer (using
MK_FP() or your compiler's eqivalent) before it can be used to access
memory.
Note that this function calls EMMgetframeaddr() internally and
allocates a temporary buffer for it on the stack. Therefore, depending
on how many page frames the system has, this function may require many
bytes of stack space. There is an absolute top limit of 60 page frames
in a system, so not more than 60 * sizeof(frameinfo) bytes will ever be
needed.
_EMMerror should be checked after calling this function.
EMMgetname() - obtain string name associated with an EMS handle
------------
int EMMgetname(int handle, char *name);
int EMMsetname(int handle, char *name);
EMMgetname() returns (as a null-terminated string) the name, if any,
assigned to an EMS handle. Real names are only implemented in EMS
version 4.0. Under earlier versions, this function fills the name buffer
with nulls ('\0'), which is also the return under version 4.0 when no
name has been associated with the given handle. The buffer pointed to by
name must be at least nine characters long (since an EMS name may be up
to eight characters long and there must be room for a terminating null).
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMsetname() allows the association of a name up to eight characters
long with an EMS handle. It only works for EMS version 4.0; under
earlier versions, it returns the error EMM_BADVERS. Version independence
has been abandoned in this case because the main purpose of associating
a name with an EMS handle is to allow several different programs to
recognize shared data. While EMSIF could implement a naming function
within itself, the names would not be visible outside the program
assigning the name, defeating the purpose of doing so in the first
place.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMgetnumframe() - obtain number of EMS page frames
----------------
int EMMgetnumframe(void);
See EMMgetframeaddr().
EMMgetsinfraddr() - get segment address of one EMS page frame
-----------------
unsigned int EMMgetsinfraddr(int frame);
See EMMgetframeaddr().
EMMgetversion() - obtain EMS version implemented by EMS driver
---------------
int EMMgetversion(void);
This function returns the EMS version implemented by the EMS driver.
The version number is in packed BCD format as in the global variable
_EMMversion, and is in fact the same value. _EMMerror should be checked
after calling this function.
EMMicopyfrom() - copy data by intervals from EMS
--------------
int EMMicopyfrom(unsigned long nelem, int elsize, unsigned int byteskip,
int handle, unsigned long foffset,
unsigned char far *dest);
int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
unsigned char far *source,
int handle, unsigned long foffset);
EMMicopyfrom() is a macro (in C) or inline function (in C++) which
calls _EMMicopyfrom(). It allows painless copying of array elements from
expanded memory to conventional memory. EMS mapping, calculation of
addresses, skipping of unwanted elements, etc., are all handled by the
function. Elements spread across more than 64K and/or totalling more
than 64K in length can be copied without special treatment.
Nelem elements are copied, each of which is elsize bytes long, with
byteskip bytes between elements at both source and destination. The
elements are copied from the EMS pages owned by handle, starting at byte
offset foffset, to conventional memory starting at dest. Dest must be a
far pointer; a near pointer can be converted to a far pointer with a cast
when the function is called. Foffset is converted as in EMMcopyfrom().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMicopyto() is a macro (in C) or inline function (in C++) which
calls _EMMicopyto(). It allows painless copying of array elements from
conventional memory to expanded memory. EMS mapping, calculation of
addresses, skipping of unwanted elements, etc., are all handled by the
function. Elements spread across more than 64K and/or totalling more
than 64K in length can be copied without special treatment.
Nelem elements are copied, each of which is elsize bytes long, with
byteskip bytes between elements at both source and destination. The elements
are copied from conventional memory starting at source, to the EMS pages
owned by handle, starting at byte offset foffset. Source must be a far
pointer; a near pointer can be converted to a far pointer with a cast when
the function is called. Foffset is converted as in EMMcopyfrom().
If nelem or elsize is zero, the function returns immediately without
error. Elsize must be in the range 0 through 16384, or the function will
return with error EMM_ELTOOBIG (in _EMMerror). Byteskip must be in the
range 0 through 32768, or the function will return with error
EMM_SKTOOBIG.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
For EMS versions below 4.0, these functions leave the last logical
page accessed mapped into page frame 2 because there is no unmapping
service. This can cause trouble if you map that logical page into
another page frame in an EMS implementation that does not support
aliasing properly. If you must mix calls to EMMmappage() and the copying
functions, it is recommended that for versions below 4.0 you map some
other logical page into page frame 2 before mapping the desired page.
Alternatively, using page frame 2 to access logical pages is guaranteed
to work properly except for logical pages which you have explicitly
mapped elsewhere.
EMMicopyto() - copy data by intervals to EMS
------------
int EMMicopyto(unsigned long nelem, int elsize, unsigned int byteskip,
unsigned char far *source,
int handle, unsigned long foffset);
See EMMicopyfrom().
EMMlibinit() - initialize EMSIF
------------
int EMMlibinit(void);
EMMlibinit() initializes EMSIF. Any other EMSIF function will return
with error EMM_NOINIT (in _EMMerror) if called before EMMlibinit() has
been called. This function returns 0 on success, EMMOOPS on error, or
NOEMM if no EMS driver is detected. If EMMOOPS is returned, the specific
error may be determined from _EMMerror. Note that EMSIF will not
initialize if the EMS driver claims that fewer than four EMS page frames
exist, since that is a violation of the EMS specification and the driver
may have other anomalies that EMSIF does not know how to handle.
Detection of the EMS driver relies on DOS services, so this library
cannot be used in a device driver as it stands. If you need this library
for a device driver or other program that cannot access DOS services,
you can buy the source (it's cheap) and easily modify EMMlibinit() to
use another method of detection. There are no other calls to DOS
services in EMSIF. The method used was chosen for its reliability;
there is another method, suitable for use in device drivers, which is
not as reliable and typically is useful _only_ for device drivers.
EMMmappage() - map an EMS logical page into an EMS page frame
------------
int EMMmappage(int frameno, int handle, int logpage);
int EMMunmapframe(int frameno);
EMMmappage() maps a logical page into an EMS page frame so that it
can be accessed. The logical page logpage belonging to handle is mapped
into page frame number frameno.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMunmapframe() unmaps the logical page currently mapped into page
frame number frameno, if any, leaving nothing mapped into that page
frame. This function only works under EMS versions 4.0 and up; version
independence has been abandoned in this case because earlier versions do
not provide this functionality and there is no good way to fake it.
EMMunmapframe() places EMM_BADVERS in _EMMerror if the EMS version is
below 4.0.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror.
EMMrealloc() - change size of an allocated block of EMS
------------
int EMMrealloc(int handle, unsigned long bytes);
int EMMreallocpages(int handle, int pages);
EMMrealloc() adjusts the size of the previously allocated EMS block
referenced by handle to be the smallest number of pages which contain
the given number of bytes, and returns an EMS handle which may or may
not be different from the old handle. If it is different, the old handle
is invalid. The contents of the block are preserved as far as possible.
If the new size is smaller, the contents of the block are truncated; if
larger, the additional bytes at the end of the block are undefined.
If the new number of pages is the same as that currently allocated to
the handle, EMMrealloc() returns immediately without error. EMMrealloc()
works best under EMS versions 4.0 and up, where an actual reallocation
service is available. Under earlier versions, EMSIF allocates a new
block and copies the contents of the old block, meaning that there must
be enough free EMS to allocate a new block of the desired size. If there
is not enough free EMS, the old block is left intact.
_EMMerror should be checked after calling this function.
EMMreallocpages() adjusts the size of the previously allocated EMS
block referenced by handle to be the given number of pages, and returns
an EMS handle which may or may not be different from the old handle. If
it is different, the old handle is invalid. The contents of the block
are preserved as far as possible. If the new size is smaller, the
contents of the block are truncated; if larger, the contents of the
additional pages at the end of the block are undefined.
If the new number of pages is the same as that currently allocated to
the handle, EMMreallocpages() returns immediately without error.
EMMreallocpages() works best under EMS versions 4.0 and up, where an
actual reallocation service is available. Under earlier versions, EMSIF
allocates a new block and copies the contents of the old block, meaning
that there must be enough free EMS to allocate a new block of the
desired size. If there is not enough free EMS, the old block is left
intact.
_EMMerror should be checked after calling this function.
EMMreallocpages() - change size of an allocated block of EMS
-----------------
int EMMreallocpages(int handle, int pages);
See EMMrealloc().
EMMrestore() - restore an EMS mapping from a save buffer
------------
int EMMrestore(void *saveblock);
void *EMMsave(void);
int EMMsrinit(void *(*mallocfunc)(size_t));
EMMrestore() restores an EMS mapping that has earlier been saved in a
save buffer with a call to EMMsave(). The contents of the frame cache
are invalidated, since the format of the contents of the save buffer
varies from one EMS driver to the next and it is thus not possible to
determine what will be mapped into the cached frame when the restore is
done. EMMrestore() does not deallocate the save buffer.
This function returns 0 on success or EMMOOPS on error. The specific
error may be determined from _EMMerror. It is an error if this function
is called before EMMsrinit() has been called.
EMMsave() allocates a save buffer (see EMMsrinit(), below) and saves
the current EMS mapping into it. The current EMS mapping is not changed,
nor are the contents of the frame cache invalidated. This function
returns the pointer returned by the allocation function (see below).
_EMMerror should be checked after calling this function. It is an
error if this function is called before EMMsrinit() has been called.
EMMsrinit() initializes the save/restore capability of EMSIF. It
takes a pointer to a memory-allocation function which is used by
EMMsave() to allocate save buffers. Malloc() is compatible in all memory
models, but any function which works the same way (returns a void
pointer of the size normal for the memory model (near or far), takes a
single parameter of type size_t which is the number of bytes to
allocate, and returns NULL (0) if the memory cannot be allocated) can
also be used. Note that the function will never be required to allocate
more than 255 bytes in one call.
EMMsrinit() will fail to initialize and return EMM_BADVERS if the EMS
version is 3.0. Since it did not initialize, EMMsave() and EMMrestore()
will not work either.
_EMMerror should be checked after calling this function.
For more information on frame caching and suggestions on using
save/restore, see sections III.3 and III.4 respectively.
EMMsave() - save an EMS mapping into a save buffer
---------
void *EMMsave(void);
See EMMrestore().
EMMsetname() - associate string name with an EMS handle
------------
int EMMsetname(int handle, char *name);
See EMMgetname().
EMMsrinit() - initialize save/restore
-----------
int EMMsrinit(void *(*mallocfunc)(size_t));
See EMMrestore().
EMMunmapframe() - remove logical page mapped into a page frame
---------------
int EMMunmapframe(int frameno);
See EMMmappage().
V. ERROR CODES
--------------
This section is a list of the error codes to which the global variable
_EMMerror may be set, and the values and meanings thereof.
V.1 INTERNAL ERRORS
-------------------
Internal codes indicate an error detected by EMSIF itself.
NAME VALUE MEANING
---- ----- -------
EMM_BADVERS 0x40 Bad EMS version, earlier than 3.0.
EMM_BADOFFSET 0x41 Offset plus copy length runs off last
EMS page owned by handle.
EMM_NOFRAME 0x42 Could not find segment address of page frame
used for copying functions (frame 2).
EMM_NOINIT 0x43 EMMlibinit() must be called before any
other EMSIF function can be called.
EMM_FEWFRAMES 0x44 The EMS driver claims that there are fewer
than four page frames.
EMM_NOSR 0x45 EMMsrinit() must be called before
EMMsave() or EMMrestore() can be called.
EMM_MEMNULL 0x46 The save/restore memory allocation
function (the one passed to EMMsrinit())
returned NULL.
EMM_ELTOOBIG 0x47 The element size passed to EMMicopyto()
or EMMicopyfrom() is too big.
EMM_SKTOOBIG 0x48 The skip size passed to EMMicopyto()
or EMMicopyfrom() is too big.
V.2 EMS DRIVER ERRORS
---------------------
These codes are defined in the EMS specification and are returned by
the EMS driver. They are saved in _EMMerror by EMSIF without alteration.
NAME VALUE MEANING
---- ----- -------
EMM_SOFTERROR 0x80 Internal error exists in EMS driver (can
indicate corrupted memory image of driver)
EMM_HARDERROR 0x81 Malfunction in expanded memory hardware
EMM_BUSY 0x82 EMS driver is busy
EMM_BADHANDLE 0x83 Invalid EMS handle
EMM_UNIMP 0x84 Function not defined
EMM_NOFREEHAN 0x85 No free EMS handles
EMM_CONTEXTERR 0x86 Error in save or restore of mapping context
EMM_WAYTOOBIG 0x87 Tried to allocate more pages than physically
exist in system; no pages allocated
EMM_TOOBIG 0x88 Tried to allocate more pages than currently
available; no pages allocated
EMM_TOOSMALL 0x89 Cannot allocate 0 pages
EMM_BADLOGPAGE 0x8A Requested logical page is outside range of
pages owned by handle
EMM_BADFRAMENO 0x8B Illegal frame number in mapping request
EMM_HSTATESAVFULL 0x8C Page-mapping hardware-state save area full
EMM_MSTATESAVFULL 0x8D Mapping-context save failed; save area
already contains context associated with
specified handle
EMM_MSTATERESTERR 0x8E Mapping-context restore failed; save area
does not contain context for specified
handle
EMM_UNIMPSUB 0x8F Subfunction parameter not defined
EMM_BADATTRIB 0x90 Attribute type not defined
EMM_NOFEATURE 0x91 Feature not supported
EMM_SRCOVERWRITE 0x92 Source and destination memory regions have
same handle and overlap; requested move
was performed, but part of the source region
was overwritten
EMM_BADLENGTH 0x93 Copy length longer than actual length
EMM_CONEMSOVERLAP 0x94 Conventional memory region and expanded
memory region overlap
EMM_OFFPAGE 0x95 Specified offset outside logical page
EMM_TOOLONG 0x96 Copy length exceeds one megabyte
EMM_EMSEMSOVERLAP 0x97 Source and destination memory regions have
same handle and overlap; exchange cannot be
performed
EMM_LOST 0x98 Memory source and destination types
undefined
EMM_UNUSED 0x99 This error code is currently unused
EMM_BADALTREG 0x9A Alternate map or DMA register sets are
supported, but specified alternate register
set is not supported
EMM_NOFREEALTREG 0x9B Alternate map or DMA register sets are
supported, but all alternate register sets
are currently allocated
EMM_NOALTREG 0x9C Alternate map or DMA register sets are not
supported, specified alternate register
set is not 0
EMM_BADALTREG2 0x9D Alternate map or DMA register sets are
supported, but the alternate register set
specified is not defined or not allocated
EMM_NODEDDMA 0x9E Dedicated DMA channels are not supported
EMM_BADDEDDMA 0x9F Dedicated DMA channels are supported, but
specified DMA channel is not supported
EMM_UNKNAME 0xA0 Handle for specified name not found
EMM_NAMETAKEN 0xA1 Handle with same name already exists
EMM_ADDRWRAP 0xA2 Memory address wraps; sum of source or
destination region base address and length
exceeds one megabyte
EMM_BADPTR 0xA3 Invalid pointer passed to function, or
contents of source array corrupted
EMM_FORBIDDENFUNC 0xA4 Access to function denied by operating
system
VI. THE END
-----------
Technical support via email is available from the following addresses:
INTERNET:
The following are alternate addresses for the same place:
support@picarefy.com
picarefy!support@amc.com
picarefy!support@netcom.com
uunet!netcom!picarefy!support
COMPUSERVE:
71261,1731
GENIE:
J.BIRDSALL2
Registrations should be sent to:
(until 7/10/93)
James W. Birdsall
11112 NE 124 LN #D204
Kirkland, WA 98034
(after 7/10/93)
11106 NE 125 LN #J203
Kirkland, WA 98034
If you have an email address on any of the networks listed above,
please include it when registering, especially if you are requesting
source code. It is much easier to send the source code by email. Also,
please specify what sort of archive (ZIP, ZOO, ARC, LZH, ARJ, UNIX shar)
you can handle most easily.
VI.1 ACKNOWLEDGEMENTS
---------------------
Thanks to Bob Parsons of Parsons Technology Inc. for some good suggestions
on the documentation and for providing the original C++ header file.
Thanks to Jim Gomes of WordPerfect Inc. for suggesting that I unify
the C and C++ headers.
VI.2 TRADEMARKS
---------------
MS-Windows is a trademark of the Microsoft Corporation.
DESQview is a trademark of Quarterdeck Office Systems.
Any other trademarks in this document are property of their
respective holders.